#ifndef VECTOR_H_
#define VECTOR_H_

#include <stdio.h>
#include <math.h>

class Math;

/* Vector data structure */
class Vector3f {
public:
	float x;
	float y;
	float z;
	
	Vector3f() {x = 0; y = 0; z = 0;}
	Vector3f(float xp, float yp, float zp) {
		x = xp; y = yp; z = zp;
	}
	Vector3f(const Vector3f& v) {
		Assign(v);
	}
	
	Vector3f operator+(Vector3f v) {
		return Vector3f(x+v.x, y+v.y, z+v.z); 
	}
	Vector3f operator-(Vector3f v) {
		return Vector3f(x-v.x, y-v.y, z-v.z); 
	}
	Vector3f operator*(float i) {
		return Vector3f(x*i, y*i, z*i);
	}
	Vector3f operator/(Vector3f v) {
		return Vector3f(x/v.x, y/v.y, z/v.z); 
	}
	Vector3f operator/(int i) {
		return Vector3f(x / i, y / i, z / i);
	}
	
	Vector3f operator+=(Vector3f v) {
		x += v.x; 
		y += v.y;
		z += v.z;
		return *this;
	}
	
	Vector3f operator/=(int i) {
		x /= i; 
		y /= i;
		z /= i;
		return *this;
	}
	
	Vector3f operator/=(float i) {
		x /= i; 
		y /= i;
		z /= i;
		return *this;
	}
	
	/* unary - */
	Vector3f operator-() {
		return Vector3f(-x, -y, -z);
	}
	
		
	float Dot(Vector3f v) {
		return x*v.x + y*v.y + z*v.z;
	}
	Vector3f Cross(Vector3f v) {
		return Vector3f(y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x);
	}
	
	Vector3f operator=(Vector3f v) {
		Assign(v.x, v.y, v.z);
		return *this;
	}
	
	void Assign(float xp, float yp, float zp) {
		x = xp; y = yp; z = zp;
	}
	
	void Assign(const Vector3f& v) {
		Assign(v.x, v.y, v.z);
	}
	
	float Magnitude() {
		return sqrt(x*x + y*y + z*z);
	}
	
	Vector3f Normalize() {
		float mag = Magnitude();
		if (mag == 0) return Vector3f(x, y, z);
		return Vector3f(x/mag, y/mag, z/mag);
	}
	
	void NormalizeInterior() {
		float mag = Magnitude();
		if (mag != 0) {
			x /= mag;
			y /= mag;
			z /= mag;
		}			
	}
	
	Vector3f Multiply(Vector3f mul) {
		return Vector3f(x*mul.x, y*mul.y, z*mul.z);
	}
	
	int IsParallel(Vector3f v) {
		float sx = x / v.x;
		float sy = y / v.y;
		float sz = z / v.z;
		if (sx == sy && sy == sz)
			return 1;
		return 0;
	}
	
	static Vector3f Reflect(Vector3f pointTo, Vector3f normal) {
		return pointTo - normal*pointTo.Dot(normal)*2;
	} 
	
	const char* ToString() {
		char* str = new char[100];
		sprintf(str, "(%.2f, %.2f, %.2f)", x, y, z);
		return str;
	}
	
	void ToFloat3(float o[3]) {
		o[0] = x;
		o[1] = y;
		o[2] = z;
	}
	
	void ToFloat4(float o[4]) {
		o[0] = x;
		o[1] = y;
		o[2] = z;
		o[3] = 0;
	}
	
	void RotateArbitrary(Vector3f p, Vector3f v, float angle);
};
#endif /*VECTOR_H_*/
